由於驗證者在驗證時需要執行 burn()
與 _mint()
兩個會改動區塊鏈資料的函式,撇除 gas fee 以外,在驗證入場的時候需要考慮到效率的問題。若是每次驗證都需要驗證者打開 MetaMask,進行交易確認再送出交易,想必會花費大量的時間的,因此我想要尋找一些方式來達到可以直接透過前端來送出交易達到節省時間的功用!
我們之前有說過,像是 MetaMask 這種熱錢包是透過 Provider 與全節點互動。
但我們也可以繞過 MetaMask,直接透過私鑰與 Infura 或是 Alchemy 的節點互動直接送出交易,我想透過這個方式可以大量的節省確認交易時所需要花費的時間。
這邊我想用的是 Infura 節點供應商提供的 API 服務。
首先要安裝 dotenv 這個套件
npm install dotenv --save
在專案中建立一個 .env
的檔案,並填入以下資訊
dotenv 可以將 .env
中的環境參數載入到 process.env
中。使用的時候可以除了可以讓我們減少 import ... from
,也可以避免敏感資訊的洩漏,因此我們的專案 API
與私鑰需要躲藏在 .env
裡面。
但我認為在前端導入私鑰的這個方法是非常危險的,非常容易會遭到竊取,因此還是推薦以 MetaMask 包裝住交易再送出的方法會比較好。
ETHEREUM_NETWORK = "goerli"
INFURA_API_KEY = "<Your-API-Key>"
SIGNER_PRIVATE_KEY = "<Your-Private-Key>"
其中 INFURA_API_KEY 可以在 Infura 官網註冊。
進入 Infura 官網要先註冊,註冊後網頁可能會自動跳出 Create new Project,或是可以點擊右上角的 dash board 也可以看到同樣的東西
按下後選擇 Ethereum,輸入專案名稱,最後會創建一個專案,進入專案後便可以看到你的 INFURA_API_KEY:
再將他複製貼上即可。
這邊我想要了解 ITX 的操作流程,因此會依循 Infura 文件中的 Send Transaction 來練習。
const main = async () => {
// Configuring the connection to an Ethereum node
const network = process.env.REACT_APP_ETHEREUM_NETWORK;
const web3 = new Web3(
new Web3.providers.HttpProvider(
`https://${network}.infura.io/v3/${process.env.REACT_APP_INFURA_API_KEY}`
)
);
// Creating a signing account from a private key
const signer = web3.eth.accounts.privateKeyToAccount(
process.env.REACT_APP_SIGNER_PRIVATE_KEY
);
web3.eth.accounts.wallet.add(signer);
// Estimatic the gas limit
var limit = web3.eth.estimateGas({
from: signer.address,
to: "0xd8538ea74825080c0c80B9B175f57e91Ff885Cb4",
value: web3.utils.toWei("0.001")
}).then(console.log);
// Creating the transaction object
const tx = {
from: signer.address,
to: "0xd8538ea74825080c0c80B9B175f57e91Ff885Cb4",
value: web3.utils.numberToHex(web3.utils.toWei('0.01', 'ether')),
gas: web3.utils.toHex(limit),
nonce: web3.eth.getTransactionCount(signer.address),
maxPriorityFeePerGas: web3.utils.toHex(web3.utils.toWei('2', 'gwei')),
chainId: 5
};
let signedTx = await web3.eth.accounts.signTransaction(tx, signer.privateKey)
console.log("Raw transaction data: " + signedTx.rawTransaction)
// Sending the transaction to the network
const receipt = await web3.eth
.sendSignedTransaction(signedTx.rawTransaction)
.once("transactionHash", (txhash) => {
console.log(`Mining transaction ...`);
console.log(`https://${network}.etherscan.io/tx/${txhash}`);
});
// The transaction is now on chain!
console.log(`Mined in block ${receipt.blockNumber}`);
之前使用 MetaMask 來傳送交易給予 provider 時,我們是用 window.ethereum.request
這個方法來呼叫他,此時瀏覽器會 pop 出一個視窗請我們確認交易。
const web3 = new Web3(Web3.givenProvider);
// 我好奇的去 log 這個 Object,可以看到他寫著 proxy
console.log(web3)
$ givenProvider: Proxy > _metamask:...
在這邊我們省下了與 MetaMask 前端互動的時間,直接與 Infura 的 Provider API 做互動,也就是直接傳送 JSON-RPC 到 provider,讓 provider 與鏈上互動。
const web3 = new Web3(
new Web3.providers.HttpProvider(
`https://${network}.infura.io/v3/${process.env.REACT_APP_INFURA_API_KEY}`
)
);
之前在介紹 Signature 的時候有提到以太坊中的交易都需要透過私鑰簽章來確認是本人,才能送出這個簽章過後的交易。而少了 MetaMask 幫我們存儲私鑰,我們就必須自己存起來並用這個私鑰自行轉換成 address 等資訊。
先使用 web3.eth.accounts.privateKeyToAccount()
將私鑰轉換成 signer 這個 Object。
再使用 web3.eth.accounts.signTransaction()
簽章。(以太坊交易可見此)
const signer = web3.eth.accounts.privateKeyToAccount(
process.env.REACT_APP_SIGNER_PRIVATE_KEY
);
...
let signedTx = await web3.eth.accounts.signTransaction(tx, signer.privateKey)
隨後這邊的 Transaction 是將數量為 value
的以太幣 transfer 給地址為 to
的 EOA。
最後透過節點送出交易,就完成了,花費了 21000 gas
const receipt = await web3.eth
.sendSignedTransaction(signedTx.rawTransaction)
.once("transactionHash", (txhash) => {
console.log(`Mining transaction ...`);
console.log(`https://${network}.etherscan.io/tx/${txhash}`);
});
原本我是想說複製貼上來送出交易來看看,但其中遇到了一些問題,雖然不一定是很困難的問題,但也花費了我蠻多時間的,與大家分享。
在 React 中無法直接使用 dotenv,要將 .env 檔案中的前綴都改成 REACT_APP_
,例如你的 variable 叫做 API_KEY
,就要改成 REACT_APP_API_KEY
,並關掉重啟就可以讀到。
tx 中的 chainId 記得要改成跟你使用的網路相符(goerli:5
),否則會跳出 invalid sender
的錯誤。
今天找到了如何繞過 MetaMask 與 Provider 互動的方法,節省了與 MetaMask 互動的時間,雖然只有一點點,但當使用者非常多時累積起來還是挺可觀的。
另外 project 快到尾聲了,今天也透過學習到之前一直不了解的地方,我也意識到還有很多東西需要努力...需要再多加油了。
若有文章內有任何錯誤的地方歡迎指點與討論!非常感謝!
歡迎贊助窮困潦倒大學生
0xd8538ea74825080c0c80B9B175f57e91Ff885Cb4